package org.aplombh.java.awcing.basic.dp.compressState;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * 求把 N×M 的棋盘分割成若干个 1×2 的长方形，有多少种方案。
 * <p>
 * 例如当 N=2，M=4 时，共有 5 种方案。当 N=2，M=3 时，共有 3 种方案。
 * <p>
 * 如下图所示：
 * <p>
 * 2411_1.jpg
 * <p>
 * 输入格式
 * 输入包含多组测试用例。
 * <p>
 * 每组测试用例占一行，包含两个整数 N 和 M。
 * <p>
 * 当输入用例 N=0，M=0 时，表示输入终止，且该用例无需处理。
 * <p>
 * 输出格式
 * 每个测试用例输出一个结果，每个结果占一行。
 * <p>
 * 数据范围
 * 1≤N,M≤11
 * 输入样例：
 * 1 2
 * 1 3
 * 1 4
 * 2 2
 * 2 3
 * 2 4
 * 2 11
 * 4 11
 * 0 0
 * 输出样例：
 * 1
 * 0
 * 1
 * 2
 * 3
 * 5
 * 144
 * 51205
 */
public class DreamOfMondrian_291 {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        DreamOfMondrian dom = new DreamOfMondrian();
        while (true) {
            String s = reader.readLine();
            int n = Integer.parseInt(s.split(" ")[0]);
            int m = Integer.parseInt(s.split(" ")[1]);
            if (dom.solve(n, m) == -1)
                break;
        }

    }
}

class DreamOfMondrian {
    public static final int N = 12;
    public static final int M = 1 << N;
    long[][] f = new long[N][M]; // i-1 -> i 的第j个方案
    ArrayList<ArrayList<Integer>> state; // 行表示第i列所有情况，列表示 i -> i-1 该情况可以合法
    boolean[] st = new boolean[M]; // 存储该状态是否合法

    public DreamOfMondrian() {
        state = new ArrayList<>();
        for (int i = 0; i < M; i++) {
            state.add(new ArrayList<>());
        }
        init();
    }

    void init() {

        for (int i = 0; i < M; i++) {
            state.get(i).clear();
        }
        for (int i = 0; i < N; i++) {
            Arrays.fill(f[i], 0);
        }

        // 只有一种情况 全部不选 00000...000
        f[0][0] = 1;
    }

    public int solve(int n, int m) {
        if (n == 0 && m == 0)
            return -1;

        // 初始化state数组 和 f 数组
        init();

        // 先把不合法的方式去除  !所有列情况相同，所以只用判断一次
        for (int i = 0; i < 1 << n; i++) {
            // 存储连续未选取区域的大小，用来判断是否为奇数
            int cnt = 0;
            // 是否合法
            boolean is_valid = true;

            // 遍历每种方案的状态，提前处理判断是否合法
            // k为第几位
            for (int k = 0; k < n; k++) {

                // i >> j 取得当前行是否选取     -> 十进制转换为二进制 第j位表示第j行是否选取    -> &1 判断是否选取 选了结果为1, 1!=0 进入处理程序段
                // 如果 (i >> j & 1) != 0 表明当前未选取区域结束
                if ((i >> k & 1) != 0) {
                    // cnt & 1 != 0 表明当前为选取区域为奇数 不合法
                    if ((cnt & 1) != 0) {
                        is_valid = false;
                        break;
                    }
                    // 当前为选取区域结束
                    cnt = 0;
                } else {
                    cnt++;
                }
            }
            // 判断最后一段个数是否为奇数
            if ((cnt & 1) != 0) is_valid = false;
            // 该状态不合法
            st[i] = is_valid;
        }

        // 遍历每种情况 第j列第k种情况  !每列情况相同 所以只用判断一次
        for (int j = 0; j < 1 << n; j++) {
            // 第j-1列第k种情况
            for (int k = 0; k < 1 << n; k++) {
                // j & k 每个二进制位进行位运算当且仅当=0时两情况没有冲突 并且 第j和第k中情况合法
                if ((j & k) == 0 && st[j | k]) {
                    // i在第j种情况下 i-1在第k种情况下可选
                    state.get(j).add(k);
                }
            }
        }

        // 遍历每一列
        for (int i = 1; i <= m; i++) {
            // 便利每种情况
            for (int j = 0; j < 1 << n; j++) {
                // 遍历每种情况下的合法状态
                for (Integer k : state.get(j)) {
                    // 将每种合法状态下的取法相加
                    f[i][j] += f[i - 1][k];
                }
            }
        }

        System.out.println(f[m][0]);

        return 0;
    }
}
